import moment from "moment"; // http://momentjs.cn/ 时间计算库网址
const dateParseFormat: string[] = [
  "YYYY-MM-DDTHH:mm:ssZ",
  "YYYY-MM-DD HH:mm:ss",
  "YYYY-MM-DD HH:mm",
  "YYYY-MM-DD",
  "YYYY-MM",
  "YYYY/MM/DDTHH:mm:ssZ",
  "YYYY/MM/DD HH:mm:ss",
  "YYYY/MM/DD HH:mm",
  "YYYY/MM/DD",
  "YYYY/MM",
  "YYYY.MM.DDTHH:mm:ssZ",
  "YYYY.MM.DD HH:mm:ss",
  "YYYY.MM.DD HH:mm",
  "YYYY.MM.DD",
  "YYYY.MM",
  "HH:mm:ss",
  "HH:mm",
  "YYYY",
  "MM",
  "DD",
];
class Utils {
  /**
   * 获取随机整数
   * @param start 开始数字
   * @param end 结束数字
   */
  public getRandom(start: number, end: number): number {
    const differ: number = end - start;
    const random: number = Math.random();
    return Math.floor(start + differ * random);
  }
  /**
   * 判断值是否为空
   * @param {*} val
   */
  public empty(val: any = "") {
    if (val) {
      const val_type = typeof (val);
      if (val_type === 'object') {
        // 要判断的是【对象】或【数组】或【null】等
        if (typeof (val.length) === 'undefined') {
          if (JSON.stringify(val) === "{}") {
            return true; // 空值，空对象
          }
        } else if (val.length === 0) {
          return true; // 空值，空数组
        }
      } else if (val_type === 'string') {
        // 如果要过滤空格等字符
        const new_val = val.trim();
        if (new_val.length === 0) {
          // 空值，例如:带有空格的字符串" "。
          return true;
        }
      } else if (val_type === 'boolean') {
        if (!val) {
          return true;
        }
      } else if (val_type === 'number') {
        if (!val) {
          return true;
        }
      }
      return false; // 非空值
    } else {
      // 空值,例如：
      // (1)null
      // (2)可能使用了js的内置的名称，例如：var name=[],这个打印类型是字符串类型。
      // (3)空字符串''、""。
      if (val === 0 || val === '0') {
        return false;
      } else {
        return true;
      }
    }
  }
  /**
   * 拷贝一个新的对象
   */
  public CopyNewObject(object: any = {}): any {
    return JSON.parse(JSON.stringify(object));
  }

  /**
   * 前置补充N个指定字符
   * @param str 传入的字符
   * @param n 需要的字符长度
   * @param s 补充的字符
   */
  public PrefixInteger(str: any, n: number, s: any): any {
    return (Array(n).join(s) + str).slice(-n);
  }
  /**
   *  获取 Unix 时间戳 (秒)
   */
  public GetDateTimeUnix(): number {
    return moment().unix();
  }
  /**
   * 获取 Unix 时间戳 (毫秒)
   */
  public GetDateTimeTimestamp(): number {
    return moment().valueOf();
  }
  /**
   * go语言 返回的时间 转正常时间
   * @param format 格式和模板 YYYY-MM-DD HH:mm:ss
   */
  public GolangDateTime(value = "0001-01-01T00:00:00Z", format = "YYYY-MM-DD HH:mm:ss"): string {
    if (this.empty(value) || value === "0001-01-01T00:00:00Z") {
      return "";
    }
    return moment(value, dateParseFormat).format(format);
  }

  /**
   * go语言 返回的时间 转正常时间
   */
  public GolangDateTimeEdit(value = "0001-01-01T00:00:00Z"): any {
    if (this.empty(value) || value === "0001-01-01T00:00:00Z") {
      return "";
    }
    return new Date(value);
  }

  /**
   * go语言 返回的时间 转 Unix 时间戳 (秒)
   */
  public GolangToUnix(value = "0001-01-01T00:00:00Z"): number {
    if (this.empty(value) || value === "0001-01-01T00:00:00Z") {
      return 0;
    }
    return moment(value, dateParseFormat).unix();
  }
  /**
   * 秒数转换为 天+小时+分钟
   * @param value 要转换的分钟数
   * @param isSeconds 是否加上秒
   * @returns 放回 X天X小时X分x秒
   */
  public formatSeconds(value: any = 0, isSeconds: boolean = false) {
    let theTime: any = parseInt(value, 0); // 需要转换的时间秒
    let theTime1: any = 0; // 分
    let theTime2: any = 0; // 小时
    let theTime3: any = 0; // 天
    if (theTime > 60) {
      theTime1 = parseInt((theTime / 60) as any, 0);
      theTime = parseInt((theTime % 60) as any, 0);
      if (theTime1 > 60) {
        theTime2 = parseInt((theTime1 / 60) as any, 0);
        theTime1 = parseInt((theTime1 % 60) as any, 0);
        if (theTime2 > 24) {
          // 大于24小时
          theTime3 = parseInt((theTime2 / 24) as any, 0);
          theTime2 = parseInt((theTime2 % 24) as any, 0);
        }
      }
    }
    let result = '';
    if (isSeconds) {
      if (theTime > 0) {
        result = "" + parseInt(theTime, 0) + "秒";
      }
    }
    if (theTime1 > 0) {
      result = "" + parseInt(theTime1, 0) + "分" + result;
    }
    if (theTime2 > 0) {
      result = "" + parseInt(theTime2, 0) + "小时" + result;
    }
    if (theTime3 > 0) {
      result = "" + parseInt(theTime3, 0) + "天" + result;
    }
    return result;
  }
  /**
   * 分钟数转换为 天+小时+分钟
   * @param value 要转换的分钟数
   * @param isSeconds 是否加上秒
   * @returns 放回 X天X小时X分x秒
   */
  public formatMinute(value: any = 0, isSeconds = false) {
    return this.formatSeconds(parseInt(value, 0) * 60, isSeconds);
  }
  /**
   * 时间加指定时间
   * @param date 要加减的时间
   * @param num  要加减的数量
   * @param ft 年：years 月：months 日：days 时：hours 分：minutes 秒：seconds
   * @param format 格式和模板 YYYY-MM-DD HH:mm:ss
   */
  public DateTimeAdd(date = "", num = 0, ft = "days", format = "YYYY-MM-DD HH:mm:ss"): string {
    if (this.empty(date)) {
      return moment().add(num, ft).format(format);
    } else {
      return moment(date, dateParseFormat).add(num, ft).format(format);
    }
  }

  /**
   * 格式化 Unix 时间戳 (毫秒)为指定格式日期时间
   * @param format 格式和模板 YYYY-MM-DD HH:mm:ss
   */
  public TimestampToDateTime(time = 0, format = "YYYY-MM-DD HH:mm:ss"): string {
    if (time < 1) {
      return "";
    }
    return moment(time).format(format);
  }
  /**
   * 格式化 Unix 时间戳 (秒)为指定格式日期时间
   * @param format 格式和模板 YYYY-MM-DD HH:mm:ss
   */
  public UnixToDateTime(time = 0, format = "YYYY-MM-DD HH:mm:ss"): string {
    if (time < 1) {
      return "";
    }
    return moment.unix(time).format(format);
  }
  /**
   * 获取指定格式的日期时间
   * @param format 格式和模板 YYYY-MM-DD HH:mm:ss
   */
  public DateTime(dateString = "", format = "YYYY-MM-DD HH:mm:ss"): string {
    if (this.empty(dateString)) {
      return moment().format(format);
    } else {
      return moment(dateString, dateParseFormat).format(format);
    }
  }
  /**
   * 获取星期
   * @param isStr isStr=true，返回 星期一，星期二， false：返回数字
   * @param dateString
   */
  public getWeek(isStr = false, dateString = ""): any {
    let week = "";
    if (this.empty(dateString)) {
      week = moment().format("E");
    } else {
      week = moment(dateString, dateParseFormat).format("E");
    }
    if (isStr) {
      let res: any = "";
      switch (week) {
        case "1":
          res = "星期一";
          break;
        case "2":
          res = "星期二";
          break;
        case "3":
          res = "星期三";
          break;
        case "4":
          res = "星期四";
          break;
        case "5":
          res = "星期五";
          break;
        case "6":
          res = "星期六";
          break;
        case "7":
          res = "星期日";
          break;
      }
      return res;
    } else {
      return week;
    }
  }
  /**
   * 计算date1和date2相差多少
   * @param date1 开始时间
   * @param date2  结束数据
   * @param ft  年：years 月：months 日：days 时：hours 分：minutes 秒：seconds
   */
  public DateDiff(date1: any, date2: any, ft = "days"): number {
    const a = moment(date1, dateParseFormat);
    const b = moment(date2, dateParseFormat);
    return a.diff(b, ft);
  }
  /**
   * base64转Blob/file文件
   * @param dataURI Base64数据
   * @param dataURI 文名称，如果为空择返回 blob,否则返回file
   */
  public dataURItoBlobFile(dataURI: any, fileName: string = "") {
    const byteString = atob(dataURI.split(',')[1]);
    const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
    const ab = new ArrayBuffer(byteString.length);
    const ia = new Uint8Array(ab);
    for (let i = 0; i < byteString.length; i++) {
      ia[i] = byteString.charCodeAt(i);
    }
    const newBlob: any = new Blob([ab], { type: mimeString });
    if (fileName) {
      // newBlob.lastModifiedDate = new Date();
      newBlob.name = fileName;
    }
    return newBlob;
  }
  /**
   * 将file文件转化为base64
   * @param {*} file  二进制文件流
   * @param {*} success 成功回调函数，返回base64
   * @param {*} err 错误回调函数，返回base64
   */
  public fileToBaseURL(file: File, success: any = () => false, err: any = () => false) {
    // 创建读取文件对象
    const fileReader = new FileReader();
    // 如果file没定义返回null
    if (this.empty(file.name) && file.size > 0) {
      return err("文件不能为空");
    }
    // 读取file文件,得到的结果为base64位
    fileReader.readAsDataURL(file);
    fileReader.onload = (e: any) => {
      // 把读取到的base64
      const imgBase64Data = e.target.result;
      success(imgBase64Data);
    };
  }
  /**
   * 递归文件转base64
   * @param files 文件数组
   * @param {} success 成功回调函数
   * @param {} err 错误回调函数
   */
  public recursionFileToBaseURL(files: File[], success: any = () => false, err: any = () => false) {
    const base64s: any[] = [];
    const toBaseURL: any = (index: number = 0, fbase64: any[] = []) => {
      this.fileToBaseURL(files[index], (fileData: any) => {
        fbase64.push(fileData);
        if (index >= files.length - 1) {
          success(fbase64);
        } else {
          toBaseURL(index + 1, fbase64);
        }
      }, (e: any) => err());
    };
    toBaseURL(0, base64s);
  }
  /**
   * canvas压缩图片
   * @param {} file 文件二进制流 必传
   * @param {} param 参数obj
   * @param {} param.compressSize 目标压缩大小 不传初始赋值 0.6 MB
   * @param {} param.imgSize 输出图片宽度和高度最大值 不传初始赋值1080，等比缩放不用传高度
   * @param {} param.fileName 输出图片名称 不传初始赋值  文件原来名称
   * @param {} param.quality 压缩图片程度 不传初始赋值0.8。值范围0~1
   * @param {} param.fileType 返回图片类型 file返回 File。base64返回 Base64, blob返回 Blob
   * @param {} success 成功回调函数
   * @param {} err 错误回调函数
   */
  public compressImage(file: File, param: any = {}, success: any = () => false, err: any = () => false) {
    if (this.empty(file.name) && file.size > 0) {
      return err("图片文件为空");
    }
    // 得到文件类型
    if (file.type.indexOf("image") == -1) {
      return err('只能压缩图片文件');
    }
    // 给参数附初始值
    param.compressSize = param.hasOwnProperty("compressSize") ? param.compressSize : 0.6;
    param.imgSize = param.hasOwnProperty("imgSize") ? param.imgSize : 1080;
    param.fileName = param.hasOwnProperty("fileName") ? param.fileName : file.name;
    param.quality = param.hasOwnProperty("quality") ? param.quality : 1;
    param.isBase64 = param.hasOwnProperty("fileType") ? param.isBase64 : "file";
    // 如果当前size比目标size小，直接输出
    const size = file.size;
    if (param.compressSize > (size / 1024 / 1024)) {
      return success(file);
    }
    // 读取file文件,得到的结果为base64位
    this.fileToBaseURL(file, (base64: any) => {
      if (base64) {
        const image = new Image();
        image.src = base64;
        image.onload = () => {
          // 获得长宽比例
          const scale: number = image.width / image.height;
          // 创建一个canvas
          const canvas = document.createElement('canvas');
          // 获取上下文
          const context: CanvasRenderingContext2D = canvas.getContext('2d') as any;
          // 计算压缩后的图片大小
          let imgWidth = 0;
          let imgHeight = 0;
          if (image.width > image.height) {
            if (image.width < param.imgSize) {
              imgWidth = image.width;
              imgHeight = image.height;
            } else {
              imgWidth = param.imgSize;
              imgHeight = parseInt((imgWidth / scale) as any, 0);
            }
          } else {
            if (image.height < param.imgSize) {
              imgWidth = image.width;
              imgHeight = image.height;
            } else {
              imgHeight = param.imgSize;
              imgWidth = parseInt((imgHeight * scale) as any, 0);
            }
          }
          canvas.width = imgWidth;
          canvas.height = imgHeight;
          // 把图片绘制到canvas上面
          context.drawImage(image, 0, 0, canvas.width, canvas.height);
          // 压缩图片，获取到新的base64Url
          const newImageData = canvas.toDataURL(file.type, param.quality);
          if (param.fileType == "base64") {
            success(newImageData);
          } else if (param.fileType == "file") {
            // 将base64转化成文件流
            const resultFile = this.dataURItoBlobFile(newImageData, file.name);
            success(resultFile);
          } else if (param.fileType == "blob") {
            // 将base64转化成blob
            const resultFile = this.dataURItoBlobFile(newImageData);
            success(resultFile);
          }
        };
      } else {
        err("获取base64图片失败");
      }
    }, (e: any) => err(e));
  }
  /**
   * 递归压缩多张图片
   * @param files 图片文件数组
   * @param {} param 参数obj
   * @param {} param.compressSize 目标压缩大小 不传初始赋值 0.6 MB
   * @param {} param.imgSize 输出图片宽度和高度最大值 不传初始赋值1080，等比缩放不用传高度
   * @param {} param.fileName 输出图片名称 不传初始赋值  文件原来名称
   * @param {} param.quality 压缩图片程度 不传初始赋值0.8。值范围0~1
   * @param {} param.fileType 返回图片类型 file返回 File。base64返回 Base64, blob返回 Blob
   * @param {} success 成功回调函数
   * @param {} err 错误回调函数
   */
  public recursionCompressImage(files: File[], param: any = {}, success: any = () => false, err: any = () => false) {
    const images: any[] = [];
    const cmpImg: any = (index: number = 0, imgs: any[] = []) => {
      this.compressImage(files[index], param, (fileData: any) => {
        imgs.push(fileData);
        if (index >= files.length - 1) {
          success(imgs);
        } else {
          cmpImg(index + 1, imgs);
        }
      }, (e: any) => err());
    };
    cmpImg(0, images);
  }
  /**
   * Uint8Array转字符串
   */
  public Uint8ArrayToString(fileData: Uint8Array): string {
    let dataString = "";
    for (const item of fileData) {
      dataString += String.fromCharCode(item);
    }
    return dataString;
  }
  /**
   * 字符串转Uint8Array
   */
  public stringToUint8Array(str: string): Uint8Array {
   const buffer = [];
    for (const i of str) {
        const _code = i.charCodeAt(0);
        if (_code < 0x80) {
            buffer.push(_code);
        } else if (_code < 0x800) {
            buffer.push(0xc0 + (_code >> 6));
            buffer.push(0x80 + (_code & 0x3f));
        } else if (_code < 0x10000) {
            buffer.push(0xe0 + (_code >> 12));
            buffer.push(0x80 + (_code >> 6 & 0x3f));
            buffer.push(0x80 + (_code & 0x3f));
        }
    }
    return Uint8Array.from(buffer);
  }

}

const utils: Utils = new Utils();
export default utils;
